package RSA;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.nio.charset.StandardCharsets;

/**
 * Java RSA 非对称加密解密简单案例（公钥加密、私钥解密）
 */
public class RSA_Demo {
    // 算法常量
    private static final String ALGORITHM = "RSA";
    private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding"; // 填充方式必须指定，否则报错
    private static final int KEY_SIZE = 2048; // 密钥长度（2048/4096，1024已不安全）

    public static void main(String[] args) {
        try {
            // 1. 生成 RSA 公私钥对（实际应用中需安全存储私钥，公钥可公开）
            KeyPair keyPair = generateKeyPair();
            String publicKeyStr = encodeBase64(keyPair.getPublic().getEncoded()); // 公钥（Base64编码）
            String privateKeyStr = encodeBase64(keyPair.getPrivate().getEncoded()); // 私钥（Base64编码）

            System.out.println("生成的公钥（Base64编码）：" + publicKeyStr);
            System.out.println("生成的私钥（Base64编码）：" + privateKeyStr);
            System.out.println("=====================================");

            // 2. 待加密的明文（支持中文，RSA 适合短文本，建议不超过117字节）
            String plainText = "Hello RSA！这是Java非对称加密案例";
            System.out.println("原始明文：" + plainText);
            System.out.println("=====================================");

            // 3. 公钥加密
            String cipherText = encrypt(plainText, publicKeyStr);
            System.out.println("公钥加密后的密文（Base64编码）：" + cipherText);
            System.out.println("=====================================");

            // 4. 私钥解密
            String decryptedText = decrypt(cipherText, privateKeyStr);
            System.out.println("私钥解密后的明文：" + decryptedText);
            System.out.println("=====================================");

            // 验证加密解密一致性
            if (plainText.equals(decryptedText)) {
                System.out.println("✅ RSA 加密解密成功！明文一致");
            } else {
                System.out.println("❌ RSA 加密解密失败！明文不一致");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成 RSA 公私钥对
     */
    public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
        keyPairGenerator.initialize(KEY_SIZE, new SecureRandom()); // 安全随机数生成密钥
        return keyPairGenerator.generateKeyPair();
    }

    /**
     * 公钥加密：明文 → 密文（Base64编码）
     * @param plainText 待加密明文
     * @param publicKeyStr Base64编码的公钥
     */
    public static String encrypt(String plainText, String publicKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        // 1. Base64解码公钥字符串 → 公钥字节数组
        byte[] publicKeyBytes = decodeBase64(publicKeyStr);
        // 2. 解析公钥（X509EncodedKeySpec 是公钥的标准编码格式）
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);

        // 3. 初始化加密器
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        // 4. 加密（明文转UTF-8字节）
        byte[] cipherBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        // 5. 密文转Base64编码返回
        return encodeBase64(cipherBytes);
    }

    /**
     * 私钥解密：密文（Base64编码）→ 明文
     * @param cipherText Base64编码的密文
     * @param privateKeyStr Base64编码的私钥
     */
    public static String decrypt(String cipherText, String privateKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        // 1. Base64解码私钥字符串 → 私钥字节数组
        byte[] privateKeyBytes = decodeBase64(privateKeyStr);
        // 2. 解析私钥（PKCS8EncodedKeySpec 是私钥的标准编码格式）
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        // 3. 初始化解密器
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        // 4. 解密（密文Base64解码 → 解密 → 明文字节）
        byte[] cipherBytes = decodeBase64(cipherText);
        byte[] plainBytes = cipher.doFinal(cipherBytes);
        // 5. 明文字节转字符串
        return new String(plainBytes, StandardCharsets.UTF_8);
    }

    /**
     * Base64 编码（字节数组 → 字符串）
     */
    private static String encodeBase64(byte[] data) {
        return Base64.getEncoder().encodeToString(data);
    }

    /**
     * Base64 解码（字符串 → 字节数组）
     */
    private static byte[] decodeBase64(String dataStr) {
        return Base64.getDecoder().decode(dataStr);
    }
}